热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

更多|都会_后端面试之MySQLInnoDB一颗B+树可以存放多少行数据?

篇首语:本文由编程笔记#小编为大家整理,主要介绍了后端面试之MySQL-InnoDB一颗B+树可以存放多少行数据?相关的知识,希望对你有一定的参考价值。首发于微信公众号&

篇首语:本文由编程笔记#小编为大家整理,主要介绍了后端面试之MySQL-InnoDB一颗B+树可以存放多少行数据?相关的知识,希望对你有一定的参考价值。


首发于微信公众号:【码农在新加坡】,欢迎关注。

个人博客网站:后端面试之MySQL-InnoDB一颗B+树可以存放多少行数据?


背景

mysql的InnoDB引擎一棵B+树可以存放多少行数据?这是一个很有趣的面试题。
也许你会猜1千万,2千万,或者上亿条数据?

当你看完这篇文章,你就心中有数了。
最重要的是,这篇文章能让你更深入的理解InnoDB的B+树索引的方方面面。

看完这篇文章,你可以同时回答以下几个关于InnoDB B+树的面试题:


  • MySQL InnoDB一颗B+树能存多少数据?
  • MySQL InnoDB的B+树每个非叶子结点能有多少分支?
  • MySQL InnoDB为什么使用B+树而非B树/Hash?
  • MySQL InnoDB为什么推荐使用自增ID做主键?

InnoDB

索引类型

我们都知道,MySQL有多种储存引擎,比如:InnoDB,MyISAM,Memory,Merge,Archive,CSV,Blackhole等。
其中最常用的储存引擎就是InnoDB,所以学好InnoDB也是理解MySQL的核心。

InnoDB支持多种索引:


  • B+树索引 - 传统意义上的索引,B+树索引并不能根据键值找到具体的行数据,B+树索引只能找到行数据锁在的页,然后通过把页读到内存,再在内存中查找到行数据。B+树索引也是最常用的最为频繁使用的索引。
  • 全文索引 - 全文索引是一种比较特殊的索引,一般都是基于倒排索引来实现的,可以解决 like %xxx%语句时,索引会失效的问题。
  • 哈希索引 - 由数据库自身根据你的使用情况创建的,并不能人为的干预,所以叫作自适应哈希索引,采用的是哈希表数据结构。所以对于字典类型查询就非常的快,但是对于范围查询就无能为力啦。

而要了解InnoDB的性能关键,就是了解它的B+树索引。


文件结构

首先我们需要理解一些基础概念。

InnoDB存储引擎的最小储存单元页(Page),一个页的大小默认是是16K,我们可以通过参数自定义设置大小(修改源码重新编译)。

在InnoDB中B+树的一个节点大小为一页,也就是16k。之所以设置为一页,是因为对于大部分业务,一页就足够了。
但如果表中一行的数据长度超过了16k,这时候就会出现行溢出,溢出的行是存放在另外的地方,存放该溢出数据的页叫uncompresse blob page

如果数据库只按这样的方式存储,那么如何查找数据就成为一个问题,因为我们不知道要查找的数据存在哪个页中,也不可能把所有的页遍历一遍,那样太慢了。所以人们想了一个办法,用B+树的方式组织这些数据。


B+树

我们先将数据记录按主键进行排序,分别存放在不同的页中。除了存放数据的数据页以外,还有存放键值+指针的页。
如图中非叶子结点中存放键值和指向数据页的指针,这样的页由多个键值+指针组成。当然它也是排好序的。这样的数据组织形式,我们称为索引组织表。现在来看下,要查找一条数据,怎么查?

select * from tab where id = 5;

这里id是主键,我们通过这棵B+树来查找,首先找到根页,我们怎么知道一个表的根页在哪呢?其实每张表的根页位置在表空间文件中是固定的,即page number=3的页(找到根页后,通过二分查找法,定位到id=5的数据页中,同样通过二分查询法即可找到id=5的记录。

所有的数据都在叶子节点,且每一个叶子节点都带有指向下一个节点的指针,形成了一个有序的链表。为什么要有序呢?
其实是为了范围查询。

比如说select * from tab where id > 1 and id <100;

当找到1后&#xff0c;只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点&#xff0c;极大的提高了范围区间的查询效率。
而哈希索引对这种范围查询是无能为力的。

总结一下&#xff1a;


  1. InnoDB 存储引擎的最小存储单元是页&#xff0c;在B&#43;树中叶子节点存放数据&#xff0c;非叶子节点存放键值&#43;指针
  2. 索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中&#xff0c;进而在去数据页中查找到需要的数据。

以下为B&#43;树的优势&#xff1a;


  • 单一节点存储更多元素&#xff0c;减少IO
  • 所有查询都要找到叶子节点&#xff0c;查询稳定
  • 所有叶子节点形成有序链表&#xff0c;方便范围查询

一般性情况&#xff0c;数据库的B&#43;树的高度一般在2~4层&#xff0c;这就是说找到某一键值的行记录最多需要1到3次逻辑IO&#xff0c;速度是非常快的。&#xff08;根节点是常驻内存中的&#xff0c;所以三层树的查询只需要两次磁盘IO&#xff09;
当然&#xff0c;由上图可得&#xff0c;范围查找的IO次数取决于范围查找的数量。


储存计算

其实储存计算有一个前提&#xff0c;我们要先假设主键ID的大小和一行数据的大小&#xff1a;
我们假设主键ID为bigint类型&#xff0c;8字节。
一行数据大小为1K左右。
这样我们那么一个页可以存放 16 行这样的数据。
数据页16K是一个包含文件头/页头/页尾等结构的数据页。
所以以上只是估算。

那非叶子节点呢&#xff1f;
其实这也很好算&#xff0c;我们假设主键 ID 为 bigint 类型&#xff0c;长度为 8 字节&#xff0c;而指针大小在 InnoDB 源码中设置为 6 字节&#xff0c;这样一共 14 字节&#xff0c;我们一个页中能存放多少这样的单元&#xff0c;其实就代表有多少指针&#xff0c;即 16384/14&#61;1170

所以我们每个非叶子结点最多有1170个子节点。

那么可以算出一棵高度为 2 的 B&#43; 树&#xff0c;能存放 1170*16&#61;18720 条这样的数据记录。

根据同样的原理我们可以算出一个高度为 3 的 B&#43; 树可以存放&#xff1a; 1170*1170*16&#61;21902400 &#xff08;2100万&#xff09;条这样的记录。

那如果四层呢&#xff1a;那就是1170*1170*1170*16&#61;256亿。大部分的InnoDB的B&#43;树都是3到4层&#xff0c;3层的性能会更好。

如果主键是4字节&#xff0c;或者一行的数据更少的情况下&#xff0c;那么同样的层数能储存的行数会更多。

现在我们知道了&#xff0c;最多能存放多少数据不是固定的。一般来说我们为了保持3层的B&#43;数层数&#xff0c;大概是千万级的数据量。

这里计算目的是为了让大家更深入的了解InnoDB B&#43;树的知识&#xff0c;做到自己心中有数。其实这个面试题的意思&#xff0c;并不是为了得到一个具体的数字&#xff0c;而是分析这个问题本身。
这样你也知道你的数据表数据量到达多大之后可以开始分库分表了。


相关面试题

现在我们了解了InnoDB B&#43;树的本质&#xff0c;那么以下的几个常见的面试题相信你也有了答案。


每个非叶子结点分支数量

从上面其实我们已经得到答案了&#xff1a;


  • 如果我们的主键是bigint类型&#xff08;8字节&#xff09;&#xff0c;16384/(8&#43;6)&#61;1170
  • 如果我们的主键是int类型&#xff08;4字节&#xff09;&#xff0c;那就是16348/(4&#43;6)&#61;1634

如果你使用占用空间更大的字符串比如UUID&#xff0c;那么数量会更少。


为什么使用B&#43;树而非B树或Hash

B树
B树和B&#43;树最重要的一个区别就是B&#43;树只有叶节点存放数据&#xff0c;其余节点用来索引&#xff0c;而B树是每个索引节点都会存数据。
存数据意味着用来索引的空间变少&#xff0c;每个节点的子节点变少&#xff0c;想要存放同样的数据量需要更多的层数&#xff0c;更多的磁盘IO次数。
同时对范围查找无法像B&#43;数那样通过链表直接串联起来那么方便。

Hash
Hash的检索效率非常高&#xff0c;但是Hash只能满足 “&#61;”, “IN” 等查询&#xff0c;不能使用范围查询。
同时Hash无法利用索引的数据来进行排序。


为什么推荐使用自增ID做主键

这也是一个常见的面试题。

推荐使用自增ID做主键
通过上文我们知道InnoDB的最小储存单位是页。一个数据页存满了&#xff0c;MySQL就回去申请一个新的数据页来存数据。


  • 如果主键是自增ID&#xff0c;那么就在一页插入满才插入下一页。
  • 如果主键不是自增ID&#xff0c;为了保持B&#43;树的有序&#xff0c;会造成频繁的页分裂和页旋转&#xff0c;插入速度比较慢。

所以聚集索引的主键值应尽量是连续增长的值&#xff0c;而不是随机值(不要用随机字符串或UUID)。

对于InnoDB的主键&#xff0c;尽量用整型&#xff0c;而且是递增的整型。这样在存储/查询上都是非常高效的。

尽量使用更小的主键
在满足业务需求的情况下&#xff0c;尽量使用占空间更小的主键。


  • 主键占用空间越大&#xff0c;每个页存储的主键个数越少&#xff0c;B&#43;树的深度会变长&#xff0c;导致IO次数会变多。
  • 普通索引的叶子节点上保存的是主键 id 的值&#xff0c;如果主键 id 占空间较大的话&#xff0c;那将会成倍增加 MySQL 空间占用大小。

<全文完>

欢迎关注我的微信公众号&#xff1a;【码农在新加坡】的微信公众号&#xff0c;有更多好的技术分享。

个人博客网站&#xff1a;后端面试之MySQL-InnoDB一颗B&#43;树可以存放多少行数据&#xff1f;


推荐阅读
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
author-avatar
Icy芸土_644
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有